package com.mjkj.demo.utils;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.Encoders;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * JWT 工具类
 * 使用 HS256 (HMAC-SHA256) 算法进行签名
 * @author koen
 */
public class JwtUtil {

	// 默认密钥 - 请在生产环境中替换为安全的密钥
	private static final String DEFAULT_SECRET = "ThisIsASecretKeyWithAtLeast256BitsLength1234567890";

	// 默认过期时间 - 2小时
	private static final long DEFAULT_EXPIRE = 2 * 60 * 60 * 1000L;

	// 签发者
	private static final String ISSUER = "your-application";

	/**
	 * 生成JWT令牌
	 * @param subject 主题/用户ID
	 * @return JWT令牌
	 */
	public static String generateToken(String subject) {
		return generateToken(subject, new HashMap<>());
	}

	/**
	 * 生成JWT令牌
	 * @param subject 主题/用户ID
	 * @param claims 自定义声明
	 * @return JWT令牌
	 */
	public static String generateToken(String subject, Map<String, Object> claims) {
		return generateToken(subject, claims, DEFAULT_EXPIRE);
	}

	/**
	 * 生成JWT令牌
	 * @param subject 主题/用户ID
	 * @param claims 自定义声明
	 * @param expire 过期时间(毫秒)
	 * @return JWT令牌
	 */
	public static String generateToken(String subject, Map<String, Object> claims, long expire) {
		Date now = new Date();
		Date expireDate = new Date(now.getTime() + expire);

		return Jwts.builder()
				.setClaims(claims)                      // 自定义声明
				.setSubject(subject)                   // 主题
				.setIssuer(ISSUER)                    // 签发者
				.setIssuedAt(now)                     // 签发时间
				.setExpiration(expireDate)            // 过期时间
				.setId(UUID.randomUUID().toString())  // JWT ID
				.signWith(getSecretKey())             // 签名算法和密钥
				.compact();
	}

	/**
	 * 解析JWT令牌
	 * @param token JWT令牌
	 * @return 声明(Claims)
	 */
	public static Claims parseToken(String token) {
		return Jwts.parserBuilder()
				.setSigningKey(getSecretKey())
				.build()
				.parseClaimsJws(token)
				.getBody();
	}

	/**
	 * 验证JWT令牌是否有效
	 * @param token JWT令牌
	 * @return 是否有效
	 */
	public static boolean validateToken(String token) {
		try {
			parseToken(token);
			return true;
		} catch (JwtException | IllegalArgumentException e) {
			return false;
		}
	}

	/**
	 * 刷新JWT令牌
	 * @param token 原令牌
	 * @param expire 新的过期时间(毫秒)
	 * @return 新令牌
	 */
	public static String refreshToken(String token, long expire) {
		Claims claims = parseToken(token);
		return generateToken(claims.getSubject(), claims, expire);
	}

	/**
	 * 获取主题(用户ID)
	 * @param token JWT令牌
	 * @return 主题
	 */
	public static String getSubject(String token) {
		return parseToken(token).getSubject();
	}

	/**
	 * 生成安全的密钥
	 * @return SecretKey
	 */
	private static SecretKey getSecretKey() {
		// 将密钥字符串转为字节数组
		byte[] keyBytes = DEFAULT_SECRET.getBytes(StandardCharsets.UTF_8);
		// 使用jjwt的工具类生成符合HS256的密钥
		return Keys.hmacShaKeyFor(keyBytes);
	}

	/**
	 * 生成安全的Base64编码密钥(可用于配置文件)
	 * @return Base64编码的密钥
	 */
	public static String generateSafeSecret() {
		SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
		return Encoders.BASE64.encode(key.getEncoded());
	}

	// 测试示例
	public static void main(String[] args) {
		// 生成令牌
		String token = generateToken("user123");
		System.out.println("Generated Token: " + token);

		// 解析令牌
		Claims claims = parseToken(token);
		// 从token中拿到subject
		System.out.println("Subject: " + claims.getSubject());
		System.out.println("Issuer: " + claims.getIssuer());
		System.out.println("Expiration: " + claims.getExpiration());

		// 验证令牌
		System.out.println("Token is valid: " + validateToken(token));

		// 生成安全密钥示例
		System.out.println("Safe Secret Key: " + generateSafeSecret());
	}
}